﻿Imports System
Imports System.CodeDom
Imports System.Collections
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.ComponentModel.Design.Serialization
Imports System.Drawing
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Imports System.Workflow.ComponentModel.Compiler
Imports System.Workflow.ComponentModel.Design
Imports System.Xml

Namespace System.Workflow.ComponentModel.Serialization
    Public Class WorkflowMarkupSerializationManager
        Implements IDesignerSerializationManager, IServiceProvider
        ' Events
        Friend Custom Event FoundDefTag As EventHandler([Of] WorkflowMarkupElementEventArgs)
        Private Custom Event System.ComponentModel.Design.Serialization.IDesignerSerializationManager.ResolveName As ResolveNameEventHandler
            AddHandler(ByVal value As ResolveNameEventHandler)
            End AddHandler
            RemoveHandler(ByVal value As ResolveNameEventHandler)
            End RemoveHandler
        End Event
        Private Custom Event System.ComponentModel.Design.Serialization.IDesignerSerializationManager.SerializationComplete As EventHandler
            AddHandler(ByVal value As EventHandler)
            End AddHandler
            RemoveHandler(ByVal value As EventHandler)
            End RemoveHandler
        End Event

        ' Methods
        Public Sub New(ByVal manager As IDesignerSerializationManager)
            If (manager Is Nothing) Then
                Throw New ArgumentNullException("manager")
            End If
            Me.serializationManager = manager
            Me.AddSerializationProvider(New WellKnownTypeSerializationProvider)
            Me.AddMappings(WorkflowMarkupSerializerMapping.WellKnownMappings)
            Dim service As ITypeProvider = [TryCast](manager.GetService(GetType(ITypeProvider)),ITypeProvider)
            If (Not service Is Nothing) Then
                Me.LocalAssembly = service.LocalAssembly
            End If
            Me.designMode = (Not manager.GetService(GetType(ITypeResolutionService)) Is Nothing)
        End Sub

        Friend Sub AddMappings(ByVal mappingsToAdd As IList([Of] WorkflowMarkupSerializerMapping))
            Dim mapping As WorkflowMarkupSerializerMapping
            For Each mapping In mappingsToAdd
                If Not Me.clrNamespaceBasedMappings.ContainsKey(mapping.GetHashCode) Then
                    Me.clrNamespaceBasedMappings.Add(mapping.GetHashCode, mapping)
                End If
                Dim list As List([Of] WorkflowMarkupSerializerMapping) = Nothing
                If Not Me.xmlNamespaceBasedMappings.TryGetValue(mapping.XmlNamespace, list) Then
                    list = New List([Of] WorkflowMarkupSerializerMapping)
                    Me.xmlNamespaceBasedMappings.Add(mapping.XmlNamespace, list)
                End If
                list.Add(mapping)
                Dim list2 As List([Of] WorkflowMarkupSerializerMapping) = Nothing
                If Not Me.prefixBasedMappings.TryGetValue(mapping.Prefix, list2) Then
                    list2 = New List([Of] WorkflowMarkupSerializerMapping)
                    Me.prefixBasedMappings.Add(mapping.Prefix, list2)
                End If
                list2.Add(mapping)
            Next
        End Sub

        Public Sub AddSerializationProvider(ByVal provider As IDesignerSerializationProvider)
            If (provider Is Nothing) Then
                Throw New ArgumentNullException("provider")
            End If
            Me.serializationManager.AddSerializationProvider(provider)
        End Sub

        Friend Sub FireFoundDefTag(ByVal args As WorkflowMarkupElementEventArgs)
            If (Not Me.FoundDefTag Is Nothing) Then
                Me.FoundDefTag.Invoke(Me, args)
            End If
        End Sub

        Friend Function GetExtendedProperties(ByVal extendee As Object) As ExtendedPropertyInfo()
            Dim list As New List([Of] ExtendedPropertyInfo)
            Dim serializer As WorkflowMarkupSerializer
            For Each serializer In Me.ExtendedPropertiesProviders
                list.AddRange(serializer.GetExtendedProperties(Me, extendee))
            Next
            Return list.ToArray
        End Function

        Public Function GetSerializer(ByVal objectType As Type, ByVal serializerType As Type) As Object
            Return Me.serializationManager.GetSerializer(objectType, serializerType)
        End Function

        Public Function GetService(ByVal serviceType As Type) As Object
            If (serviceType Is Nothing) Then
                Throw New ArgumentNullException("serviceType")
            End If
            Return Me.serializationManager.GetService(serviceType)
        End Function

        Public Overridable Function [GetType](ByVal typeName As String) As Type
            If (typeName Is Nothing) Then
                Throw New ArgumentNullException("typeName")
            End If
            Dim type As Type = Nothing
            If Me.designMode Then
                Try 
                    type = Me.serializationManager.GetType(typeName)
                Catch obj1 As Object
                End Try
            End If
            If (type Is Nothing) Then
                Dim service As ITypeProvider = [TryCast](Me.GetService(GetType(ITypeProvider)),ITypeProvider)
                If (Not service Is Nothing) Then
                    type = service.GetType(typeName, False)
                End If
            End If
            If (Not type Is Nothing) Then
                Return type
            End If
            Dim assemblyString As String = String.Empty
            Dim index As Integer = typeName.IndexOf(",")
            Dim str2 As String = typeName
            If (index > 0) Then
                assemblyString = typeName.Substring((index + 1))
                typeName = typeName.Substring(0, index)
            End If
            Dim assembly As Assembly = Nothing
            assemblyString = assemblyString.Trim
            If (assemblyString.Length <= 0) Then
                Return type
            End If
            If (assemblyString.IndexOf(","c) >= 0) Then
                Try 
                    [assembly] = Assembly.Load(assemblyString)
                Catch obj2 As Object
                End Try
            End If
            typeName = typeName.Trim
            If (Not [assembly] Is Nothing) Then
                Return [assembly].GetType(typeName, False)
            End If
            Return Type.GetType(str2, False)
        End Function

        Public Overridable Function [GetType](ByVal xmlQualifiedName As XmlQualifiedName) As Type
            If (xmlQualifiedName Is Nothing) Then
                Throw New ArgumentNullException("xmlQualifiedName")
            End If
            Dim xmlns As String = xmlQualifiedName.Namespace
            Dim typeName As String = WorkflowMarkupSerializer.EnsureMarkupExtensionTypeName(xmlQualifiedName)
            Dim type As Type = WorkflowMarkupSerializerMapping.ResolveWellKnownTypes(Me, xmlns, typeName)
            If (type Is Nothing) Then
                Dim list As List([Of] WorkflowMarkupSerializerMapping) = Nothing
                If Not Me.xmlNamespaceBasedMappings.TryGetValue(xmlns, list) Then
                    Dim matchingMappings As IList([Of] WorkflowMarkupSerializerMapping) = Nothing
                    Dim collectedMappings As IList([Of] WorkflowMarkupSerializerMapping) = Nothing
                    WorkflowMarkupSerializerMapping.GetMappingsFromXmlNamespace(Me, xmlns, matchingMappings, collectedMappings)
                    Me.AddMappings(matchingMappings)
                    Me.AddMappings(collectedMappings)
                    list = New List([Of] WorkflowMarkupSerializerMapping)(matchingMappings)
                End If
                Dim mapping As WorkflowMarkupSerializerMapping
                For Each mapping In list
                    Dim assemblyName As String = mapping.AssemblyName
                    Dim clrNamespace As String = mapping.ClrNamespace
                    Dim name As String = xmlQualifiedName.Name
                    If (clrNamespace.Length > 0) Then
                        name = (clrNamespace & "." & xmlQualifiedName.Name)
                    End If
                    If assemblyName.Equals(Assembly.GetExecutingAssembly.FullName, StringComparison.Ordinal) Then
                        type = Assembly.GetExecutingAssembly.GetType(name)
                    ElseIf (assemblyName.Length = 0) Then
                        If (Not Me.localAssembly Is Nothing) Then
                            type = Me.localAssembly.GetType(name)
                        End If
                    Else
                        Dim str6 As String = name
                        If (assemblyName.Length > 0) Then
                            str6 = (str6 & ", " & assemblyName)
                        End If
                        Try 
                            type = Me.GetType(str6)
                        Catch obj1 As Object
                        End Try
                        If (type Is Nothing) Then
                            type = Me.GetType(name)
                            If ((Not type Is Nothing) AndAlso Not type.AssemblyQualifiedName.Equals(str6, StringComparison.Ordinal)) Then
                                type = Nothing
                            End If
                        End If
                    End If
                    If (Not type Is Nothing) Then
                        Return type
                    End If
                Next
            End If
            Return type
        End Function

        Public Overridable Function GetXmlQualifiedName(ByVal type As Type, <Out> ByRef prefix As String) As XmlQualifiedName
            If (type Is Nothing) Then
                Throw New ArgumentNullException("type")
            End If
            Dim str As String = If((Not type.Namespace Is Nothing), type.Namespace, String.Empty)
            Dim str2 As String = If(((Not type.Assembly Is Nothing) AndAlso (Not type.Assembly Is Me.localAssembly)), type.Assembly.FullName, String.Empty)
            Dim mapping As WorkflowMarkupSerializerMapping = Nothing
            Dim key As Integer = (str.GetHashCode Xor str2.GetHashCode)
            If Not Me.clrNamespaceBasedMappings.TryGetValue(key, mapping) Then
                Dim collectedMappings As IList([Of] WorkflowMarkupSerializerMapping) = Nothing
                WorkflowMarkupSerializerMapping.GetMappingFromType(Me, type, mapping, collectedMappings)
                Me.AddMappings(New List([Of] WorkflowMarkupSerializerMapping)(New WorkflowMarkupSerializerMapping() { mapping }))
                Me.AddMappings(collectedMappings)
            End If
            Dim name As String = WorkflowMarkupSerializer.EnsureMarkupExtensionTypeName(type)
            prefix = If(mapping.Prefix.Equals("wf", StringComparison.Ordinal), String.Empty, mapping.Prefix)
            Return New XmlQualifiedName(name, mapping.XmlNamespace)
        End Function

        Public Sub RemoveSerializationProvider(ByVal provider As IDesignerSerializationProvider)
            If (provider Is Nothing) Then
                Throw New ArgumentNullException("provider")
            End If
            Me.serializationManager.RemoveSerializationProvider(provider)
        End Sub

        Public Sub ReportError(ByVal errorInformation As Object)
            If (errorInformation Is Nothing) Then
                Throw New ArgumentNullException("errorInformation")
            End If
            Me.serializationManager.ReportError(errorInformation)
        End Sub

        Private Function System.ComponentModel.Design.Serialization.IDesignerSerializationManager.CreateInstance(ByVal type As Type, ByVal arguments As ICollection, ByVal name As String, ByVal addToContainer As Boolean) As Object Implements IDesignerSerializationManager.CreateInstance
            Return Me.serializationManager.CreateInstance(type, arguments, name, addToContainer)
        End Function

        Private Function System.ComponentModel.Design.Serialization.IDesignerSerializationManager.GetInstance(ByVal name As String) As Object Implements IDesignerSerializationManager.GetInstance
            Return Me.serializationManager.GetInstance(name)
        End Function

        Private Function System.ComponentModel.Design.Serialization.IDesignerSerializationManager.GetName(ByVal value As Object) As String Implements IDesignerSerializationManager.GetName
            Return Me.serializationManager.GetName(value)
        End Function

        Private Sub System.ComponentModel.Design.Serialization.IDesignerSerializationManager.SetName(ByVal instance As Object, ByVal name As String) Implements IDesignerSerializationManager.SetName
            Me.serializationManager.SetName(instance, name)
        End Sub


        ' Properties
        Friend ReadOnly Property ClrNamespaceBasedMappings As IDictionary([Of] Integer, WorkflowMarkupSerializerMapping)
            Get
                Return Me.clrNamespaceBasedMappings
            End Get
        End Property

        Public ReadOnly Property Context As ContextStack
            Get
                Return Me.serializationManager.Context
            End Get
        End Property

        Friend ReadOnly Property ExtendedPropertiesProviders As IList([Of] WorkflowMarkupSerializer)
            Get
                If (Me.extendedPropertiesProviders Is Nothing) Then
                    Me.extendedPropertiesProviders = New List([Of] WorkflowMarkupSerializer)
                End If
                Return Me.extendedPropertiesProviders
            End Get
        End Property

        Public Property LocalAssembly As Assembly
            Get
                Return Me.localAssembly
            End Get
            Set(ByVal value As Assembly)
                Me.localAssembly = value
            End Set
        End Property

        Friend ReadOnly Property PrefixBasedMappings As Dictionary([Of] String, List([Of] WorkflowMarkupSerializerMapping))
            Get
                Return Me.prefixBasedMappings
            End Get
        End Property

        Protected Friend Property SerializationManager As IDesignerSerializationManager
            Get
                Return Me.serializationManager
            End Get
            Set(ByVal value As IDesignerSerializationManager)
                Me.serializationManager = value
                Me.serializationManager.AddSerializationProvider(New WellKnownTypeSerializationProvider)
            End Set
        End Property

        Friend ReadOnly Property SerializationStack As Stack
            Get
                Return Me.serializationStack
            End Get
        End Property

        Private ReadOnly Property System.ComponentModel.Design.Serialization.IDesignerSerializationManager.Properties As PropertyDescriptorCollection
            Get
                Return Me.serializationManager.Properties
            End Get
        End Property

        Friend ReadOnly Property WorkflowMarkupStack As ContextStack
            Get
                Return Me.workflowMarkupStack
            End Get
        End Property

        Friend Property WriterDepth As Integer
            Get
                Return Me.writerDepth
            End Get
            Set(ByVal value As Integer)
                Me.writerDepth = value
            End Set
        End Property

        Friend ReadOnly Property XmlNamespaceBasedMappings As IDictionary([Of] String, List([Of] WorkflowMarkupSerializerMapping))
            Get
                Return Me.xmlNamespaceBasedMappings
            End Get
        End Property


        ' Fields
        Private clrNamespaceBasedMappings As Dictionary([Of] Integer, WorkflowMarkupSerializerMapping) = New Dictionary([Of] Integer, WorkflowMarkupSerializerMapping)
        Private designMode As Boolean
        Private extendedPropertiesProviders As List([Of] WorkflowMarkupSerializer)
        Private localAssembly As Assembly
        Private prefixBasedMappings As Dictionary([Of] String, List([Of] WorkflowMarkupSerializerMapping)) = New Dictionary([Of] String, List([Of] WorkflowMarkupSerializerMapping))
        Private serializationManager As IDesignerSerializationManager
        Private serializationStack As Stack = New Stack
        Private workflowMarkupStack As ContextStack = New ContextStack
        Private writerDepth As Integer
        Private xmlNamespaceBasedMappings As Dictionary([Of] String, List([Of] WorkflowMarkupSerializerMapping)) = New Dictionary([Of] String, List([Of] WorkflowMarkupSerializerMapping))

        ' Nested Types
        Private NotInheritable Class WellKnownTypeSerializationProvider
            Implements IDesignerSerializationProvider
            ' Methods
            Private Function System.ComponentModel.Design.Serialization.IDesignerSerializationProvider.GetSerializer(ByVal manager As IDesignerSerializationManager, ByVal currentSerializer As Object, ByVal objectType As Type, ByVal serializerType As Type) As Object Implements IDesignerSerializationProvider.GetSerializer
                If ((serializerType Is GetType(WorkflowMarkupSerializer)) AndAlso (Not objectType Is Nothing)) Then
                    If ((TypeProvider.IsAssignable(GetType(ICollection([Of] String)), objectType) AndAlso TypeProvider.IsAssignable(objectType, GetType(List([Of] String)))) AndAlso Not TypeProvider.IsAssignable(GetType(Array), objectType)) Then
                        Return New StringCollectionMarkupSerializer
                    End If
                    If GetType(Color).IsAssignableFrom(objectType) Then
                        Return New ColorMarkupSerializer
                    End If
                    If GetType(Size).IsAssignableFrom(objectType) Then
                        Return New SizeMarkupSerializer
                    End If
                    If GetType(Point).IsAssignableFrom(objectType) Then
                        Return New PointMarkupSerializer
                    End If
                    If (objectType Is GetType(CodeTypeReference)) Then
                        Return New CodeTypeReferenceSerializer
                    End If
                End If
                Return Nothing
            End Function

        End Class
    End Class
End Namespace

